home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 8 / QRZ Ham Radio Callsign Database - Volume 8.iso / mac / files / t_sys5 / unixcpio.gz / unixnet.cpio / pc100.c < prev    next >
C/C++ Source or Header  |  1994-07-11  |  12KB  |  492 lines

  1. /* Interface driver for the PACCOMM PC-100 board for the IBM PC */
  2. /* UNFINISHED, DOESN'T WORK YET - work in progress by Bdale */
  3. /* currently only attempting to use the AMD7910 on Channel A */
  4.  
  5. #include <stdio.h>
  6. #include "global.h"
  7. #include "mbuf.h"
  8. #include "iface.h"
  9. #include "pc100.h"
  10. #include "8530.h"
  11. #include "ax25.h"
  12. #include "trace.h"
  13.  
  14. struct pc100 pc100[NPC];
  15. void pc0vec(),write_scc(),rts();
  16. void (*pchandle[])() = { pc0vec };
  17. struct hdlc hdlc[2*NPC];
  18. int16 npc;
  19.  
  20. /* Branch table for interrupt handler */
  21. void htxint(), hexint(), hrxint(), hspint();
  22. static void (*svec[])() = {
  23.     htxint, hexint, hrxint, hspint
  24. };
  25.  
  26. /* Master interrupt handler for the PC-100 card. All interrupts come
  27.  * here first, then are switched out to the appropriate routine.
  28.  */
  29. void
  30. pcint(dev)
  31. int16 dev;
  32. {
  33.     register char iv;
  34.     register int16 pcbase;
  35.     struct hdlc *hp;
  36.  
  37.     pc100[dev].ints++;
  38.     pcbase = pc100[dev].addr;
  39.  
  40.     /* Read interrupt vector, including status, from channel B */
  41.     iv = read_scc(CTL+pcbase+CHANB,R2);
  42.  
  43.     hp = &hdlc[2 * dev + ((iv & 0x80)? 0 : 1)];
  44.  
  45.     /* Now switch to appropriate routine */
  46.     (*svec[(iv>>1) & 0x3])(hp);
  47.  
  48.     /* Reset interrupt pending state (register A only) */
  49.     write_scc(CTL+pcbase+CHANA,R0,RES_H_IUS);
  50.  
  51.     /* Wang the 8530 hardware interrupt acknowledge line - Bdale */
  52.     inportb(pcbase+INTACK);
  53. }
  54. /* HDLC Special Receive Condition interrupt
  55.  * The most common event that triggers this interrupt is the
  56.  * end of a frame; it can also be caused by a receiver overflow.
  57.  */
  58. static void
  59. hspint(hp)
  60. register struct hdlc *hp;
  61. {
  62.     register char c;
  63.  
  64.     hp->spints++;
  65.     c = read_scc(CTL+hp->base,R1);    /* Fetch latched bits */
  66.  
  67.     if((c & (END_FR|CRC_ERR)) == END_FR && hp->rcvbuf != NULLBUF
  68.         && hp->rcvbuf->cnt > 1){
  69.         /* End of valid frame */
  70.         hp->rcvbuf->cnt--;    /* Toss 1st crc byte */
  71.         enqueue(&hp->rcvq,hp->rcvbuf);
  72.         hp->rcvbuf = NULLBUF;
  73.         hp->rcvcnt++;
  74.     } else {
  75.         /* An overflow or CRC error occurred; restart receiver */
  76.         hp->crcerr++;
  77.         if(hp->rcvbuf != NULLBUF){
  78.             hp->rcp = hp->rcvbuf->data;
  79.             hp->rcvbuf->cnt = 0;
  80.         }
  81.     }
  82.     write_scc(CTL+hp->base,R0,ERR_RES);
  83. }
  84. /* HDLC SIO External/Status interrupts
  85.  * The only one of direct interest is a receiver abort; the other
  86.  * usual cause is a change in the modem control leads, so kick the
  87.  * transmit interrupt routine.
  88.  */
  89. static void
  90. hexint(hp)
  91. register struct hdlc *hp;
  92. {
  93.     hp->exints++;
  94.     hp->status = read_scc(CTL+hp->base,R0);    /* Fetch status */
  95.     if((hp->status & BRK_ABRT) && hp->rcvbuf != NULLBUF){
  96.         hp->aborts++;
  97.         /* Restart receiver */
  98.         hp->rcp = hp->rcvbuf->data;
  99.         hp->rcvbuf->cnt = 0;
  100.     }
  101.     write_scc(CTL+hp->base,R0,RES_EXT_INT);
  102.     write_scc(CTL+hp->base,R0,RES_H_IUS);
  103.     /* Kick the transmit interrupt routine for a possible modem change */
  104.     htxint(hp);
  105. }
  106. /* HDLC receiver interrupt handler. Allocates buffers off the freelist,
  107.  * fills them with receive data, and puts them on the receive queue.
  108.  */
  109. static void
  110. hrxint(hp)
  111. register struct hdlc *hp;
  112. {
  113.     register struct mbuf *bp;
  114.     register int16 base;
  115.  
  116.     hp->rxints++;
  117.     base = hp->base;
  118.     /* Allocate a receive buffer if not already present */
  119.     if((bp = hp->rcvbuf) == NULLBUF){
  120.         bp = hp->rcvbuf = alloc_mbuf(hp->bufsiz);
  121.         if(bp == NULLBUF){
  122.             /* No memory, abort receiver */
  123.             hp->nomem++;
  124.             write_scc(CTL+base,R3,ENT_HM|RxENABLE|RxCRC_ENAB|Rx8);
  125.             (void) inportb(base+DATA);
  126.             return;
  127.         }
  128.         hp->rcp = hp->rcvbuf->data;
  129.     }
  130.     while(read_scc(CTL+base,R0) & Rx_CH_AV){
  131.         if(bp->cnt++ >= hp->bufsiz){
  132.             /* Too large; abort the receiver, toss buffer */
  133.             hp->toobig++;
  134.             write_scc(CTL+base,R3,ENT_HM|RxENABLE|RxCRC_ENAB|Rx8);
  135.             (void) inportb(base+DATA);
  136.             free_p(bp);
  137.             hp->rcvbuf = NULLBUF;
  138.             break;
  139.         }
  140.         /* Normal save */
  141.         *hp->rcp++ = inportb(base+DATA);
  142.     }
  143. }
  144. int ctswait;
  145. /* HDLC transmit interrupt service routine
  146.  *
  147.  * The state variable tstate, along with some static pointers,
  148.  * represents the state of the transmit "process".
  149.  */
  150. static void
  151. htxint(hp)
  152. register struct hdlc *hp;
  153. {
  154.     register int16 base;
  155.     char i_state,c;
  156.  
  157.     i_state = disable();
  158.     hp->txints++;
  159.     base = hp->base;
  160.     while(read_scc(CTL+base,R0) & Tx_BUF_EMP){
  161.         switch(hp->tstate){
  162.         /* First here for efficiency */
  163.         case ACTIVE:        /* Sending frame */
  164.             if(pullup(&hp->sndbuf,&c,1) == 1){
  165.                 outportb(base+DATA,c);
  166.             } else {
  167.                 /* Do this after sending the last byte */
  168.                 write_scc(CTL+base,R0,RES_Tx_P);
  169.                 if((hp->sndbuf = dequeue(&hp->sndq)) == NULLBUF){
  170.                     switch(hp->mode){
  171.                     case CSMA:
  172.                         /* Begin transmitter shutdown */
  173.                         hp->tstate = FLUSH;
  174.                         break;
  175.                     case FULLDUP:
  176.                         hp->tstate = IDLE;
  177.                         break;
  178.                     }
  179.                 }
  180.             }
  181.             continue;
  182.         case IDLE:
  183.             /* Transmitter idle. Find a frame for transmission */
  184.             if((hp->sndbuf = dequeue(&hp->sndq)) == NULLBUF)
  185.                 goto ret;
  186.  
  187.         case DEFER:    /* note fall-thru */
  188.             if(hp->mode == CSMA && (hp->status & DCD)){
  189.                 hp->tstate = DEFER;
  190.                 goto ret;
  191.             }
  192.             rts(base,ON);    /* Transmitter on */
  193.         case KEYUP:    /* note fall-thru */
  194.             if((hp->status & CTS) == 0){
  195.                 ctswait++;
  196.                 hp->tstate = KEYUP;
  197.                 goto ret;
  198.             }
  199.             write_scc(CTL+base,R0,RES_Tx_CRC);
  200.             pullup(&hp->sndbuf,&c,1);
  201.             outportb(hp->base+DATA,c);
  202.             hp->tstate = ACTIVE;
  203.             write_scc(CTL+base,R0,RES_EOM_L);
  204.             continue;
  205.         case FLUSH:    /* Sending flush character */
  206.             outportb(hp->base+DATA,(char)0);
  207.             hp->tstate = FIN2;
  208.             continue;
  209.         case FIN2:
  210.             write_scc(CTL+base,R0,SEND_ABORT);
  211.             hp->tstate = IDLE;
  212.             rts(base,OFF);
  213.             write_scc(CTL+base,R0,RES_Tx_P);
  214.             continue;
  215.         }
  216.     }
  217. ret:    restore(i_state);
  218. }
  219.  
  220. /* Set request-to-send on modem */
  221. static void
  222. rts(base,x)
  223. int16 base;
  224. int x;
  225. {
  226.     int16 cmd;
  227.  
  228.     if(x)
  229.         cmd = TxCRC_ENAB | RTS | TxENAB | Tx8 | DTR;
  230.     else
  231.         cmd = TxCRC_ENAB | TxENAB | Tx8 | DTR;
  232.     write_scc(CTL+base,R5,cmd);
  233. }
  234. /* (re)Initialize HDLC controller parameters */
  235. static int
  236. hdlcparam(hp)
  237. register struct hdlc *hp;
  238. {
  239.     int16 tc;
  240.     char i_state;
  241.     register int16 base;
  242.  
  243.     /* Initialize 8530 channel for SDLC operation */
  244.     base = hp->base;
  245.     i_state = disable();
  246.  
  247.     switch(base & 2){
  248.     case 0:
  249.         write_scc(CTL+base,R9,CHRA);    /* Reset channel A */
  250.         break;
  251.     case 2:
  252.         write_scc(CTL+base,R9,CHRB);    /* Reset channel B */
  253.         break;
  254.     }
  255.     /* Wait/DMA disable, Int on all Rx chars + spec condition,
  256.      * parity NOT spec condition, TxINT enable, Ext Int enable
  257.      */
  258.     write_scc(CTL+base,R1,INT_ALL_Rx | TxINT_ENAB | EXT_INT_ENAB);
  259.  
  260.     /* Dummy interrupt vector, will be modified by interrupt type
  261.      * (This probably isn't necessary)
  262.      */
  263.     write_scc(CTL+base,R2,0);
  264.  
  265.     /* 8 bit RX chars, auto enables off, no hunt mode, RxCRC enable,
  266.      * no address search, no inhibit sync chars, enable RX
  267.      */
  268.     write_scc(CTL+base,R3,Rx8|RxCRC_ENAB|RxENABLE);
  269.  
  270.     /* X1 clock, SDLC mode, Sync modes enable, parity disable
  271.      * (Note: the DPLL does a by-32 clock division, so it's not necessary
  272.      * to divide here).
  273.      */
  274.     write_scc(CTL+base,R4,X1CLK | SDLC | SYNC_ENAB);
  275.  
  276.     /* DTR On, 8 bit TX chars, no break, TX enable, SDLC CRC,
  277.      * RTS off, TxCRC enable
  278.      */
  279.     write_scc(CTL+base,R5,DTR|Tx8|TxENAB|TxCRC_ENAB);
  280.  
  281.     /* SDLC flag */
  282.     write_scc(CTL+base,R7,FLAG);
  283.  
  284.     /* No reset, status low, master int enable, enable lower chain,
  285.      * no vector, vector includes status
  286.      */
  287.     write_scc(CTL+base,R9,MIE|NV|VIS);
  288.     /* CRC preset 1, NRZI encoding, no active on poll, flag idle,
  289.      * flag on underrun, no loop mode, 8 bit sync
  290.      */
  291.     write_scc(CTL+base,R10,CRCPS|NRZI);
  292.  
  293.     /* Board no longer channel-specific for clk.  The board should be set
  294.      * up to run from the 4.9152Mhz onboard crystal connected to PCLK.
  295.      * Both channels get receive clock at 32x from PCLK via the DPLL,
  296.      * with TRxC as an output, via a 4040 div by 32 counter to RTxC set
  297.      * us as an input to provide the transmit clock.
  298.      */
  299.  
  300.     /*            TRxC = BR Generator Output, TRxC O/I,
  301.      *          transmit clock = RTxC pin, 
  302.      *          receive clock = DPLL output
  303.      */
  304.     write_scc(CTL+base,R11,TRxCBR|TRxCOI|TCRTxCP|RCDPLL);
  305.  
  306.     /* Compute and load baud rate generator time constant
  307.      * DPLL needs x32 clock
  308.      * XTAL is defined in pc100.h to be the crystal clock / (2 * 32)
  309.      */
  310.     tc = XTAL/(hp->speed) - 2;
  311.     write_scc(CTL+base,R12,tc & 0xff);
  312.     write_scc(CTL+base,R13,(tc >> 8) & 0xff);
  313.  
  314.     write_scc(CTL+base,R14,SNRZI);    /* Set NRZI mode */
  315.     write_scc(CTL+base,R14,SSBR);    /* Set DPLL source = BR generator */
  316.     write_scc(CTL+base,R14,SEARCH);    /* Enter search mode */
  317.     /* Set baud rate gen source = PCLK, enable baud rate gen */
  318.     write_scc(CTL+base,R14,BRENABL|BRSRC);
  319.  
  320.     /* Break/abort IE, TX EOM IE, CTS IE, no SYNC/HUNT IE, DCD IE,
  321.      * no Zero Count IE
  322.      */
  323.     write_scc(CTL+base,R15,BRKIE|TxUIE|CTSIE|DCDIE);
  324.  
  325.     restore(i_state);
  326.     if(hp->mode == FULLDUP){
  327.         rts(base,ON);
  328.     } else if(hp->tstate == IDLE){
  329.         rts(base,OFF);
  330.     }
  331.     return 0;
  332. }
  333. /* Attach a PC-100 interface to the system
  334.  * argv[0]: hardware type, must be "pc100"
  335.  * argv[1]: I/O address, e.g., "0x380"
  336.  * argv[2]: vector, e.g., "2"
  337.  * argv[3]: mode, must be:
  338.  *        "ax25" (AX.25 UI frame format)
  339.  * argv[4]: interface label, e.g., "pc0"
  340.  * argv[5]: receiver packet buffer size in bytes
  341.  * argv[6]: maximum transmission unit, bytes
  342.  * argv[7]: interface speed, e.g, "9600"
  343.  */
  344. int
  345. pc_attach(argc,argv)
  346. int argc;
  347. char *argv[];
  348. {
  349.     register struct interface *if_pca,*if_pcb;
  350.     extern struct interface *ifaces;
  351.     struct hdlc *hp;
  352.     int dev;
  353.     int pc_init();
  354.     void dopc();
  355.     int pc_stop();
  356.     int ax_send();
  357.     int ax_output();
  358.     int pc_raw();
  359.     void (*getirq())();    /* Getirq is a function returning a pointer to
  360.                  * a function returning void */
  361.  
  362.     if(npc >= NPC){
  363.         printf("Too many pc100 controllers\n");
  364.         return -1;
  365.     }
  366.     dev = npc++;
  367.  
  368.     /* Initialize hardware-level control structure */
  369.     pc100[dev].addr = htoi(argv[1]);
  370.     pc100[dev].vec = htoi(argv[2]);
  371.     /* Initialize modems */
  372.     outportb(pc100[dev].addr + MODEM_CTL,(char)0x22);
  373.  
  374.     /* Save original interrupt vector */
  375.     pc100[dev].oldvec = getirq(pc100[dev].vec);
  376.     /* Set new interrupt vector */
  377.     if(setirq(pc100[dev].vec,pchandle[dev]) == -1){
  378.         printf("IRQ %u out of range\n",pc100[dev].vec);
  379.         npc--;
  380.         return -1;
  381.     }
  382.     /* Create interface structures and fill in details */
  383.     if_pca = (struct interface *)calloc(1,sizeof(struct interface));
  384.     if_pcb = (struct interface *)calloc(1,sizeof(struct interface));
  385.  
  386.     if_pca->name = malloc((unsigned)strlen(argv[4])+1);
  387.     strcpy(if_pca->name,argv[4]);
  388.     if_pcb->name = malloc((unsigned)strlen(argv[4])+1);
  389.     strcpy(if_pcb->name,argv[4]);
  390.     if_pcb->name[strlen(argv[4]) - 1]++;    /* kludge */
  391.     if_pcb->mtu = if_pca->mtu = atoi(argv[6]);
  392.     if_pca->dev = 2*dev;
  393.     if_pcb->dev = 2*dev + 1;
  394.     if_pcb->recv = if_pca->recv = dopc;
  395.     if_pcb->stop = if_pca->stop = pc_stop;
  396.     if_pcb->output = if_pca->output = ax_output;
  397.     if_pcb->raw = pc_raw;
  398.  
  399.     if(strcmp(argv[3],"ax25") == 0){
  400.  
  401.         axarp();
  402.         if(mycall.call[0] == '\0'){
  403.             printf("set mycall first\n");
  404.             free((char *)if_pca);
  405.             free((char *)if_pcb);
  406.             return -1;
  407.         }        
  408.         if_pcb->send = if_pca->send = ax_send;
  409.         if(if_pcb->hwaddr == NULLCHAR)
  410.             if_pcb->hwaddr = malloc(sizeof(mycall));
  411.         memcpy(if_pcb->hwaddr,(char *)&mycall,sizeof(mycall));
  412.     } else {
  413.         printf("Mode %s unknown for interface %s\n",
  414.             argv[3],argv[4]);
  415.         free((char *)if_pca);
  416.         free((char *)if_pcb);
  417.         return -1;
  418.     }
  419.     if_pca->next = if_pcb;
  420.     if_pcb->next = ifaces;
  421.     ifaces = if_pca;
  422.  
  423.     hp = &hdlc[2*dev+1];
  424.     hp->speed = (int16)atoi(argv[7]);
  425.     hp->base = pc100[dev].addr + CHANB;
  426.     hp->bufsiz = atoi(argv[5]);
  427.     hdlcparam(hp);
  428.  
  429.     hp = &hdlc[2*dev];
  430.     hp->speed = (int16)atoi(argv[7]);
  431.     hp->base = pc100[dev].addr + CHANA;
  432.     hp->bufsiz = atoi(argv[5]);
  433.     hdlcparam(hp);
  434.  
  435.     /* Clear mask (enable interrupt) in 8259 interrupt controller */
  436.     clrbit(INTMASK,(char)(1<<pc100[dev].vec));
  437.  
  438.     return 0;
  439. }
  440. void
  441. dopc(interface)
  442. struct interface *interface;
  443. {
  444.     struct hdlc *hp;
  445.     struct mbuf *bp;
  446.  
  447.     hp = &hdlc[interface->dev];
  448.     while((bp = dequeue(&hp->rcvq)) != NULLBUF){
  449.         hp->rcvcnt--;
  450.         dump(interface,IF_TRACE_IN,TRACE_AX25,bp);
  451.         ax_recv(interface,bp);
  452.     }    
  453. }
  454. int
  455. pc_stop(iface)
  456. struct interface *iface;
  457. {
  458.     int16 dev;
  459.  
  460.     dev = iface->dev;
  461.     if(dev & 1)
  462.         return 0;
  463.     dev >>= 1;    /* Convert back into PC100 number */
  464.     /* Turn off interrupts */
  465.     maskoff(pc100[dev].vec);
  466.  
  467.     /* Restore original interrupt vector */
  468.     setirq(pc100[dev].vec,pc100[dev].oldvec);
  469.  
  470.     /* Force hardware reset */
  471.     write_scc(CTL+pc100[dev].addr + CHANA,R9,FHWRES);
  472.     return 0;
  473. }
  474.     
  475. /* Send raw packet on PC-100 */
  476. int
  477. pc_raw(interface,bp)
  478. struct interface *interface;
  479. struct mbuf *bp;
  480. {
  481.     char kickflag;
  482.     struct hdlc *hp;
  483.  
  484.     dump(interface,IF_TRACE_OUT,TRACE_AX25,bp);
  485.     hp = &hdlc[interface->dev];
  486.     kickflag = (hp->sndq == NULL);
  487.     enqueue(&hp->sndq,bp);
  488.     if(kickflag)
  489.         htxint(&hdlc[interface->dev]);
  490.     return 0;
  491. }
  492.